home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Just Call Me Internet
/
Just Call Me Internet.iso
/
prog
/
atari
/
c
/
zsource
/
expandar.c
< prev
next >
Wrap
C/C++ Source or Header
|
1988-05-18
|
15KB
|
701 lines
/*
* Examine each argument given to expandargs()
* If it is a directory, then expand it
* to all its component files, recursively
* till you bottom out.
* If it is not a directory, then just pass it on.
*
* Inputs: routine, argc, argv
* Outputs: nargc, nargv (calls routine(nargc, nargv))
* To test: compile with -DTEST
* define MWC if using Mark Williams C
* run with a directory as an arg
* Author: JRB bammi@mandrill.ces.CWRU.edu
* Requirements: Mark Williams C or Alcyon C
* Wants lots of Dynamic memory. It
* all depends upon how many files you
* have. Use the -P option to prune
* out subdirectories and do things
* one at a time, if you keep running
* out of memory.
* With Mark Williams i use _stksize = 128K
* With Alcyon i use memory model 2 (half of
* of avail memory) in GEMSTART.S
*
* WARNINGS: Be CAREFUL about the 40 folder bug. Use
* GEMBOOT or FOLDRXXX when dealing with
* a deeply nested file structure.
*
* Added -P name prune option at the suggestion of dietz@zhmti
* Multiple -P's may be given on the command line.
* -P name may be given anywhere on the command line. -P name
* will prune the subdirectories named as arguement to -P.
* ie: when the program is decending the file hierarchy it
* will not visit the pruned branches.
* NOTE that the option is -P and not -p
* (-p is a valid sz option).
* NOTE that the arguement given to -P can be the name
* of a file or a directory. In case it is a file,
* that file is skipped.
*
*/
/*
* Expand argc, so that the called routine(nargc,nargv) receives only
* filenames, in nargv[][]
*
************************************************************************
* *
* WARNING: Be CAREFUL about the 40 folder bug. Use *
* GEMBOOT or FOLDRXXX when dealing with *
* a deeply nested file structure. *
* *
************************************************************************
*
* Jwahar R. Bammi
* usenet: mandrill!bammi@{decvax,sun}.UUCP
* csnet: bammi@mandrill.ces.CWRU.edu
* arpa: bammi@mandrill.ces.CWRU.edu
* CompuServe: 71515,155
*
*/
#ifdef TEST
#include <stdio.h>
#include <osbind.h>
#include <ctype.h>
#endif
#ifdef TRUE
#undef TRUE
#endif
#ifdef OK
#undef OK
#endif
#ifdef FALSE
#undef FALSE
#endif
#define TRUE 1
#define OK 0
#define FALSE 0
#define Realloc realloc
#ifdef TEST
struct stat
{
char st_sp1[21]; /* Junk */
char st_mode; /* File attributes */
int st_time; /* Mod Time */
int st_date; /* Mod date */
long st_size; /* File size */
char st_name[14]; /* File name */
};
#endif
typedef struct _prunelist {
char *name; /* name of subdirectory to prune */
struct _prunelist *next; /* ptr to next */
} PRUNELIST;
static char *ProgName;
static PRUNELIST *PruneList = (PRUNELIST *)NULL; /* Head of PruneList */
static char **CopyToNargv();
static char **ExpandStack();
static void FreeStack();
static void FreeNargv();
static void FreePrune();
static void FreeUp();
static int PushDir();
static char *PopDir();
static int ProcessDirs();
static PRUNELIST *AddPrune();
static int OnPruneList();
static int isdir();
extern int existd();
expandargs(routine, argc, argv)
int (*routine)();
int argc;
char **argv;
{
register int status;
int nargc;
char **nargv;
extern char **CopyToNargv();
extern PRUNELIST *AddPrune();
extern int existd();
nargc = 0;
nargv = (char **)NULL;
ProgName = *argv;
/* copy argv[0] blindly */
if((nargv = CopyToNargv(*argv, nargc, nargv)) == (char **)NULL)
{
FreeUp(nargc, nargv);
return(~OK);
}
nargc++;
while((--argc) > 0)
{
argv++;
if(**argv == '-')
{
/* copy any options except -P */
#ifdef TEST
/* some shell pass -P as -p */
if( ((*argv)[1] == 'P') || ((*argv)[1] == 'p'))
#else
if( (*argv)[1] == 'P')
#endif
{
if((--argc) <= 0)
{
fprintf(STDERR,"no argument given to -P\n");
FreeUp(nargc, nargv);
return(~OK);
}
if((PruneList = AddPrune(PruneList,*++argv))
== (PRUNELIST *)NULL)
{
FreeUp(nargc, nargv);
return(~OK);
}
}
else
{
if((nargv = CopyToNargv(*argv, nargc, nargv))
== (char **)NULL)
{
FreeUp(nargc, nargv);
return(~OK);
}
else
nargc++;
}
}
else
{
/* If its not on the PruneList then */
if(!OnPruneList(PruneList, *argv))
{
/* if it is a directory, push it */
if(existd(*argv))
{
if((status = PushDir(*argv)) != OK)
{
FreeUp(nargc, nargv);
return(status);
}
}
else
{
/* it is NOT a directory, copy to nargv */
if((nargv = CopyToNargv(*argv, nargc, nargv))
== (char **)NULL)
{
FreeUp(nargc, nargv);
return(~OK);
}
else
nargc++;
}
}
}
} /* while */
/* process pushed directories if any */
if((status = ProcessDirs(&nargc, &nargv)) != OK)
{
FreeUp(nargc, nargv);
return(status);
}
/* else Free the Stack and Prune List, call *routine */
FreeStack();
FreePrune();
status = (*routine)(nargc, nargv);
FreeNargv(nargc, nargv);
return status;
}
/*
* Expand nargv by an element and copy a String into the new element
*
*/
static char **CopyToNargv(string, nargc, nargv)
char *string;
int nargc;
char **nargv;
{
extern char *malloc(), *Realloc(), *strcpy();
extern int strlen();
/* expand nargv by 1 element */
if(nargv == (char **)NULL)
/* do it with malloc for the first one */
nargv = (char **)malloc(sizeof(char **));
else
/* do it with Realloc for others */
nargv = (char **)Realloc(nargv, (nargc+1)*sizeof(char **));
if(nargv == (char **)NULL)
{
/* failed to get memory */
fprintf(STDERR,"%s(CopyToNargv()): Out of Memory\n", ProgName);
return ((char **)NULL);
}
/* Get mem for string */
if(( nargv[nargc] = malloc(strlen(string)+1)) == (char *)NULL)
{
/* failed to get memory */
fprintf(STDERR,"%s(CopyToNargv()): Out of Memory\n", ProgName);
return ((char **)NULL);
}
/* copy string into nargv[nargc] */
(void)strcpy( nargv[nargc], string);
return(nargv);
}
static char **Stack = (char **)NULL; /* directory stack */
static char StackSize = 0; /* Size of current Stack */
static int Top = -1;
#define STACK_EMPTY (Top < 0)
#define CHUNKSIZE 16
/*
* Grow the Stack by one chunk of CHUNKSIZE elements
*
*/
static char **ExpandStack(Stack)
char **Stack;
{
extern char *malloc(), *Realloc();
/* Grow Stack */
if(Stack == (char **)NULL)
/* with malloc */
Stack = (char **)malloc(CHUNKSIZE * sizeof(char **));
else
/* with Realloc */
Stack = (char **)Realloc(Stack, (StackSize+CHUNKSIZE) *
sizeof(char **));
if(Stack == (char **)NULL)
{
/* outa mem */
fprintf(STDERR,"%s(ExpandStack()): Out of Memory\n", ProgName);
return((char **)NULL);
}
StackSize += CHUNKSIZE;
return(Stack);
}
/*
* Free the Stack
*
*/
static void FreeStack()
{
if(StackSize > 0)
(void)free(Stack);
Stack = (char **)NULL;
StackSize = 0;
Top = -1;
}
/*
* Free Nargv
*
*/
static void FreeNargv(nargc, nargv)
int nargc;
char *nargv[];
{
register int i;
for(i = 0; i < nargc; i++)
(void)free(nargv[i]);
if(nargc > 0)
(void)free(nargv);
}
/*
* Free the PruneList
*
*/
static void FreePrune()
{
register PRUNELIST *p, *next;
for(p = PruneList; p != (PRUNELIST *)NULL; p = next)
{
next = p->next;
(void)free(p);
}
PruneList = (PRUNELIST *)NULL;
}
/*
* FreeUp before bad exit
*
*/
static void FreeUp(nargc, nargv)
int nargc;
char **nargv;
{
FreeStack();
FreePrune();
FreeNargv(nargc, nargv);
}
/*
* Push a directory name on Stack
*
*/
static int PushDir(name)
char *name;
{
extern char *malloc(), *strcpy();
extern int strlen();
extern char **ExpandStack();
#ifdef DDEBUG
printf("PushDir: %s\n", name);
#endif
++Top;
if(Top >= StackSize)
{
if((Stack = ExpandStack(Stack)) == (char **)NULL)
return(~OK);
}
if((Stack[Top] = malloc(strlen(name)+1)) == (char *)NULL)
{
/* outa mem */
fprintf(STDERR,"%s(PushDir()): Out of Memory\n", ProgName);
return(~OK);
}
(void)strcpy(Stack[Top], name);
return(OK);
}
/*
* Pop a directory name from the stack
*
*/
static char *PopDir()
{
register char *r;
extern char **ShrinkStack();
if(STACK_EMPTY)
return ((char *)NULL);
r = Stack[Top];
Top--;
return(r);
}
static int BadStatus = FALSE;
#define BADSTATUS (BadStatus != FALSE)
#define MAXNAMLEN 128
/*
* Process directories on the Stack, by adding all the
* files in a directory to nargv.
*/
static int ProcessDirs(nargc, nargv)
int *nargc;
char ***nargv;
{
register char *name;
register struct stat *dp;
register int status, slashp;
char path[MAXNAMLEN+1];
extern char **CopyToNargv();
extern char *PopDir();
extern char *alltolower();
if(BADSTATUS)
return(~OK);
if(STACK_EMPTY)
/* Nothing more to do */
return(OK);
/* Pop a directory from Stack and process */
if((name = PopDir()) == (char *)NULL)
{
/* Oh Oh */
fprintf(STDERR,"Internal Error (BUG), PopDir returns NULL\n");
BadStatus = (~FALSE);
return(~OK);
}
strcpy(path, name);
if(path[(strlen(path)-1)] == '\\')
{
strcat(path,"*.*");
slashp = TRUE;
}
else
{
strcat(path,"\\*.*");
slashp = FALSE;
}
/* Open the directory */
if(Fsfirst(path, 0x0020| 0x0010 | 0x0001) != 0)
{
/* trouble opening directory */
fprintf(STDERR,"Trouble opening %s\n",path);
/* set BADSTATUS and return */
BadStatus = (~FALSE);
return(~OK);
}
/* get the DTA */
dp = (struct stat *)Fgetdta();
/* for each entry in the directory, if it is a file
add to nargv. If it is a directory, Push it onto
the directory stack.
*/
do
{
if(! ((strcmp(dp->st_name,".") == 0) ||
(strcmp(dp->st_name,"..") == 0)) )
{
strcpy(path, name);
if(!slashp)
strcat(path,"\\");
strcat(path,dp->st_name);
/* If this path is on the PruneList skip */
if(OnPruneList(PruneList, alltolower(path)))
continue;
if(!isdir(path, dp->st_mode))
{
/* not a dir -- add this to nargv */
if((*nargv = CopyToNargv(path, *nargc, *nargv))
== (char **)NULL)
{
BadStatus = (~FALSE);
return(~OK);
}
else
{
*nargc += 1;
}
}
else
{
/* Push This directory */
if((status = PushDir(path)) != OK)
{
BadStatus = (~FALSE);
return(status);
}
}
}
} while(Fsnext() == 0);
free(name); /* done with this directory */
/* go do the rest */
return (ProcessDirs(nargc, nargv));
}
/*
* Add a name to PruneList
*
*/
static PRUNELIST *AddPrune(list, name)
PRUNELIST *list;
char *name;
{
extern char *malloc();
register PRUNELIST *new;
if((new = (PRUNELIST *)malloc(sizeof(PRUNELIST))) == (PRUNELIST *)NULL)
{
/* outa mem */
fprintf(STDERR,"%s(AddPrune()): Out of Memory\n", ProgName);
return(new);
}
new->name = name;
new->next = list;
return(new);
}
/*
* Search for name on PruneList
*
*/
static int OnPruneList(list, name)
register PRUNELIST *list;
register char *name;
{
for(; list != (PRUNELIST *)NULL; list = list->next)
{
if(strcmp(list->name, name) == 0)
return(~FALSE);
}
return(FALSE);
}
/*
* test if a subdirectory exists, without touching the DTA
* include special case of 'D:\' that Fsfirst does'nt handle correctly
*/
static int isdir(name, attr)
register char *name;
register int attr;
{
/* assuming the DTA buffer is already set up */
extern long drv_map;
register int drive;
if(attr & 0x0010)
return TRUE;
/* Gemdos doesn't like d:\ style dirs */
if((name[3] == '\0') && (name[2] == '\\') && (name[1] == ':'))
{
drive = name[0];
if(isupper(drive))
drive = tolower(drive);
drive = drive - 'a';
if((drv_map & (1L << drive)) == 0)
return FALSE;
else
return TRUE;
}
/* Nor does Gemdos understand '.' or '..' */
/* Hey Atari, don't you guys ever test anything */
if((strcmp(name,".") == 0) || (strcmp(name,"..") == 0) ||
(strcmp(name,".\\") == 0) || (strcmp(name,"..\\") == 0))
return TRUE;
return FALSE;
}
#ifdef TEST
/*
* convert string to all lower case
*/
char *alltolower(s)
char *s;
{
register char *p;
for(p = s; *p != '\0'; p++)
if(isupper(*p))
*p = tolower(*p);
return s;
}
/*
* test if a subdirectory exists
* include special case of 'D:\' that Fsfirst does'nt handle correctly
* (this routine not needed for zmdm, as it is defined in common.c)
*/
int existd(name)
register char *name;
{
/* assuming the DTA buffer is already set up */
/* assumes drv_map has been read in drv_map externally */
extern long drv_map;
register int drive;
extern struct stat statbuf;
if (Fsfirst(name , 0x0021|0x0010) == 0)
{
if((statbuf.st_mode & 0x0010) == 0x0010)
return TRUE;
}
/* Gemdos doesn't like d:\ style dirs */
if((name[3] == '\0') && (name[2] == '\\') && (name[1] == ':'))
{
drive = name[0];
if(isupper(drive))
drive = tolower(drive);
drive = drive - 'a';
if((drv_map & (1L << drive)) == 0)
return FALSE;
else
return TRUE;
}
/* Nor does Gemdos understand '.' or '..' */
/* Hey Atari, don't you guys ever test anything */
if((strcmp(name,".") == 0) || (strcmp(name,"..") == 0) ||
(strcmp(name,".\\") == 0) || (strcmp(name,"..\\") == 0))
return TRUE;
return FALSE;
}
int MAIN(argc, argv)
int argc;
char **argv;
{
register int i;
for(i = 0; i < argc; i++)
printf("%d:\t%s\n", i, argv[i]);
return(0);
}
struct stat statbuf; /* Disk Transfer address for Find first etc */
long drv_map;
#ifdef MWC
long _stksize = 128L * 1024L;
#endif
#ifdef MANX
long _STKSIZ = 128L * 1024L;
#endif
main(argc, argv)
int argc;
char **argv;
{
/* Set up Dta */
Fsetdta(&statbuf);
drv_map = Drvmap();
exit(expandargs(MAIN, argc, argv));
}
#endif /* TEST */
/* -eof- */